package com.andy.buyu.server.utils;

import java.util.List;

import org.apache.commons.lang3.RandomUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.andy.buyu.server.dao.DaoUtils;
import com.andy.buyu.server.dao.DbBatch;
import com.andy.buyu.server.entity.BaseEntity;
import com.andy.buyu.server.entity.ConfAttackType;
import com.andy.buyu.server.entity.ConfFish;
import com.andy.buyu.server.entity.ConfScript;
import com.andy.buyu.server.entity.UsrGameInfo;
import com.andy.buyu.server.entity.UsrGameLog;
import com.andy.buyu.server.game.FishGame;
import com.andy.buyu.server.game.GameConf;
import com.andy.buyu.server.game.GameUser;
import com.andy.buyu.server.game.Global;
import com.andy.buyu.server.game.Room;
import com.andy.buyu.server.socket.MySocketSession;
import com.andy.buyu.server.socket.SendUtil;
import com.google.common.collect.Lists;

public class CommonUtils {

	private static Logger logger = LoggerFactory.getLogger(CommonUtils.class);
	
	/**
	 * 离开游戏
	 * @param user
	 * @param action 
	 */
	public static void outRoom(GameUser user, int action) {
		if(user == null)return;
		Room room = user.getRoom();
		if(room != null){
			int index = user.getDeskIndex();
			synchronized (room) {
				user.gameOver();
				room.logout(user,action);
			}
			SendUtil.send118(room, user);
			// 更新桌子信息
			SendUtil.send103(room, index);
			// 返回桌子信息
			SendUtil.send102(user);
		}
		
		saveDb(user.getUser(),user.getGameInfo());
		
	}
	
	/**
	 * 开火
	 * @param user
	 * @param scriptId
	 * @param x
	 * @param y
	 * @param battery 
	 */
	public static boolean fire(GameUser user,int scriptId,int x,int y, int battery) {
		FishGame game = user.getGame();
		if(game == null) return false;
		// 检测是否可以开炮
		if(!user.checkFire(battery)) return false;
		UsrGameInfo gameInfo = user.getGameInfo();
		UsrGameLog log = new UsrGameLog(gameInfo);
		int lost = 0;
		if(battery < GoConstant.BATTERY_TYPE_61 && battery != GoConstant.BATTERY_TYPE_14) { // 道具使用的炮弹不耗费金币
			lost = GameConf.baseConsume*user.getBatteryRate();
			if(lost > gameInfo.getCoin()) return false; // 金币不足
			// 费用相关处理
			gameInfo.addCoin(-lost);
			log.setLostCoin(lost);
			CommonUtils.saveDb(gameInfo,log);
			if(!user.isRobo()) {
				Global.sysCurrHave.addAndGet(lost);
			}
		}
		
		
		user.fire(battery);
		boolean isFireRocket = false;
		if(battery < GoConstant.BATTERY_TYPE_2){
			// 触发火箭炮技能
			isFireRocket = RandomUtils.nextInt(0, 100) < GameConf.rocketTriggerRate;
			if(isFireRocket){
				user.addBullet(GoConstant.BATTERY_TYPE_2, 4);
			}else {
				// 触发烈焰风暴
				checkTriggerLyfb(user);
			}
		}
		
		if(battery == GoConstant.BATTERY_TYPE_11) {
			// 弹射
			user.addBullet(GoConstant.BATTERY_TYPE_11, 1000);
		}else{
			user.addBullet(battery, 1);
		}
		
		if(scriptId > 0) {
			// 锁定攻击
			SendUtil.send206(user.getRoom(),user, lost,scriptId);
		}else {
			SendUtil.send200(user.getRoom(),user, battery,lost,x,y);
		}
		
		if(battery > GoConstant.BATTERY_TYPE_2 && user.getBattery() != battery){
			// 说明特殊炮已经打完，切换回原来的炮
			SendUtil.send203(user);
		}
		if(isFireRocket) {
			// 触发火箭炮
			SendUtil.send200(user.getRoom(), user, GoConstant.BATTERY_TYPE_2,0, 0, 0);
		}
		return true;
	}
	
	private static boolean checkTriggerLyfb(GameUser user) {
		long sysCoin = Global.sysCurrHave.get();
		if(sysCoin > GameConf.lyfbTriggerConf[0] && user.fireNum() > GameConf.lyfbTriggerConf[1]) {
			if(RandomUtils.nextInt(0, 10000) < GameConf.lyfbTriggerConf[2]) {
				user.dropShell(GoConstant.BATTERY_TYPE_14);
				SendUtil.send210(null,user);
				return true;
			}
		}
		return false;
	}

	/**
	 * 碰撞捕鱼
	 * @param yxrate 预先控制的倍率
	 */
	public static UsrGameLog catchFish(GameUser user,FishGame game, int scriptId,int bullet, int yxrate) {
		if(!game.checkFish(scriptId)) {
			logger.warn("攻击鱼类异常：{}",scriptId);
			return null;
		}
		
		UsrGameInfo gameInfo = user.getGameInfo();
		ConfScript script = GameConf.getScript(scriptId);
		ConfFish fish = GameConf.getFish(script.getFishId());
		// 检测子弹可攻击鱼类型
		if(!checkBullet(bullet,fish.getType())) return null;
		
		UsrGameLog log = new UsrGameLog(gameInfo);
		int addCoin = 0;
		int rate = -1;
		if(bullet == GoConstant.BATTERY_TYPE_22 || bullet == GoConstant.BATTERY_TYPE_30){
			// 闪电链、鱼王王攻击必然捕获
			rate = fish.tryRate(true);
		}else{
			int times = 1;
			if(bullet == GoConstant.BATTERY_TYPE_12) {
				times = 3;
			}else if(bullet == GoConstant.BATTERY_TYPE_13) {
				times = 5;
			}else if(bullet == GoConstant.BATTERY_TYPE_14) {
				// 检测是否触发延长时间
				checkYanchang(user,bullet);
			}else if(bullet == GoConstant.BATTERY_TYPE_40 || bullet == GoConstant.BATTERY_TYPE_42) {
				times = 3;
			}else if(bullet == GoConstant.BATTERY_TYPE_41) {
				times = 2;
			}
			while(rate < 0 && times-- > 0) {
				// 是否捕获
				rate = fish.tryRate(false);
			}
			// 捕获成功，特殊道具倍率
			if(rate >= 0 && bullet >= GoConstant.BATTERY_TYPE_61) {
				rate = GameConf.RSD_RATE[bullet-GoConstant.BATTERY_TYPE_61];
			}
		}
		
		int changeBat = -1; // 掉落炮弹
		if(rate >= 0){ // 捕获成功
			// 清除捕获的鱼
			game.outFish(scriptId,fish,rate);
			if(fish.getType() == 21) {
				// 获得已经发出的爆炸炮弹
				if(logger.isInfoEnabled()){
					logger.info("爆炸：{}-{}", bullet,fish.getFunc());
				}
				if(fish.getFunc() == GoConstant.BATTERY_TYPE_20){
					// 20-8方向爆炸
					user.addBullet(fish.getFunc(),8);
				}else{
					user.addBullet(fish.getFunc(),1);
				}
				
			}else if(fish.getType() == 22) {
				// 拉霸抽奖
				user.setLaba(user.getBatteryRate());
			}else if(fish.getType() == 23) {
				// 获得炮艇
				if(logger.isInfoEnabled()){
					logger.info("获得炮艇：{}-{}-{}", user.getId(),bullet,fish.getFunc());
				}
				if(user.dropShell(fish.getFunc())) {
					changeBat = fish.getFunc();
				}
			}else if(fish.getType() == 24) {
				// 鱼王
				if(logger.isInfoEnabled()){
					logger.info("获得鱼王：{}-{}", user.getId(),fish.getFunc());
				}
				List<Integer> scripts = game.getScriptsByFishId(fish.getFunc());
				if(scripts != null){
					catchMultFish(user, GoConstant.BATTERY_TYPE_30, scripts,0);
				}
			}else if(fish.getType() == 31) {
				game.setBossDead(true);
				// 海王类
				if(logger.isInfoEnabled()){
					logger.info("获得海王：{}-{}", user.getId(),fish.getFunc());
				}
				List<Integer> scripts = game.getInFishs();
				if(scripts != null){
					int yrate = 0;
					if(fish.getFunc() == GoConstant.BATTERY_TYPE_42) {
						// 预先计算倍率
						yrate = GameConf.ldjxRewardRate.selTuple().getFir();
						log.yrate(yrate);
					}
					catchMultFish(user, fish.getFunc(), scripts,yrate);
				}
			}
			log.setScriptId(scriptId);
			if(bullet == GoConstant.BATTERY_TYPE_40){
				// 海王攻击，有概率翻倍
				if(RandomUtils.nextInt(0, 100) < GameConf.rocketTriggerRate){
					rate *= 2;
					log.orate(2);
				}
			}else if(bullet == GoConstant.BATTERY_TYPE_42) {
				// 雷电觉醒攻击
				if(yxrate > 0) {
					// 翻倍
					log.orate(yxrate);
					rate *= yxrate;
				}
			}else if(bullet == GoConstant.BATTERY_TYPE_14) {
				// 烈焰风暴攻击，有概率翻倍
				if(RandomUtils.nextInt(0, 100) < GameConf.lyfbTriggerConf[4]){
					rate *= 2;
					log.orate(2);
				}
			}
			addCoin += rate*user.getBatteryRate();
			gameInfo.setWinCount(gameInfo.getWinCount()+1);
		}else{
			gameInfo.setLoseCount(gameInfo.getLoseCount()+1);
		}
		log.battary(changeBat);
		log.setRate(rate);
		log.setAddCoin(addCoin);
		if(addCoin > 0) {
			gameInfo.addCoin(addCoin);
			CommonUtils.saveDb(gameInfo,log);
			
			if(!user.isRobo()) {
				Global.sysCurrHave.addAndGet(-addCoin);
			}
		}
		
		return log;
	}

	
	private static void checkYanchang(GameUser user, int bullet) {
		if(RandomUtils.nextInt(0, 100) < GameConf.lyfbTriggerConf[3]){
			// 发送时间延长包
			logger.info("发送时间延长包:{}",user.getId());
			user.addedTime(1);
			SendUtil.send211(user, 1, 1);
		}
	}

	private static boolean checkBullet(int bullet, int fishType) {
		ConfAttackType attackType = GameConf.getAttackType(bullet);
		if(attackType != null){
			return attackType.canAttack(fishType);
		}
		return true;
	}
	
	public static void catchMultFish(GameUser user, int bullet, List<Integer> scripts, int orate) {
		List<UsrGameLog> logs = Lists.newArrayList();
		int battary = 0;
		for(Integer scriptId:scripts){
			UsrGameLog log = CommonUtils.catchFish(user,user.getGame(), scriptId, bullet,orate);
			if(log != null && log.getRate() >= 0){
				// 捕获才响应包
				logs.add(log);
				if(log.battary() > 0){
					// 取最后一个，互相覆盖
					battary = log.battary();
				}
			}
		}
		
		if(logger.isInfoEnabled()){
			logger.info("攻击多条鱼响应：{}-{}-{}", user.getId(),bullet,logs.size());
		}
		
		if(battary > 0){
			if(logger.isInfoEnabled()){
				logger.info("切换炮台：{}-{}", user.getId(),battary);
			}
			SendUtil.send207(user.getRoom(),user,bullet, logs,user);
			// 由前端触发
//			SendUtil.send203(user);
		}else {
			SendUtil.send207(user.getRoom(),user,bullet, logs,null);
		}
	}

	/**
	 * 异步批量操作
	 * @param entity
	 */
	public static void saveDb(BaseEntity... entity){
		try {
			for(BaseEntity en:entity){
				if(en.getId() != null){
					if(en instanceof UsrGameInfo){
						DbBatch.upUsrUser((UsrGameInfo) en);
					}else{
						DaoUtils.update(en);
					}
				}else{
					if(en instanceof UsrGameLog){
						DbBatch.svGameLog((UsrGameLog) en);
					}else{
						DaoUtils.insert(en);
					}
				}
			}
		} catch (Exception e) {
			logger.error("持久化异常",e);
		}
	}

	/**
	 * 后台管理调用增加金币
	 * @param id
	 * @param addCoin
	 */
	public static void addCoin(Long id, Integer addCoin) {
		MySocketSession session = Global.getSession(id);
		if(session != null){
			session.getUser().getGameInfo().addCoin(addCoin);
			SendUtil.send114(session,session.getUser());
		}else{
			UsrGameInfo gameInfo = DaoUtils.get(id, UsrGameInfo.class);
			gameInfo.addCoin(addCoin);
			saveDb(gameInfo);
		}
	}

	// 每日扣除系统资金
	public static void exchangeCoin() {
		logger.error("每日扣除系统资金开始...");
		Global.sysCurrHave.addAndGet(-GameConf.sysDayDec);
		
		UsrGameLog log = new UsrGameLog();
		log.setUid(0L);
		log.setCoin(0L);
		log.setLostCoin(0);
		log.setRate(0);
		log.setAddCoin(GameConf.sysDayDec);
		saveDb(log);
	}

}
